/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Text;

namespace Galaxium.Protocol.Msn
{
	public abstract class SLPMessage
	{
		MsnSession _session;
		MIMECollection _mimeHeader = new MIMECollection ();
		MIMECollection _mimeBody = new MIMECollection ();
		
		public MsnSession Session
		{
			get { return _session; }
		}
		
		protected abstract string StartLine { get; set; }
		
		public MIMECollection MIMEHeader
		{
			get { return _mimeHeader; }
		}
		
		public MIMECollection MIMEBody
		{
			get { return _mimeBody; }
		}
		
		public IMsnEntity To
		{
			get { return (IMsnEntity)_session.FindEntity (_mimeHeader["To"]); }
			set { _mimeHeader["To"] = string.Format ("<{0}:{1}>", MsnNetworkUtility.Name (value.Network), value.UniqueIdentifier); }
		}
		
		public IMsnEntity From
		{
			get { return (IMsnEntity)_session.FindEntity (_mimeHeader["From"]); }
			set { _mimeHeader["From"] = string.Format ("<{0}:{1}>", MsnNetworkUtility.Name (value.Network), value.UniqueIdentifier); }
		}
		
		public string Via
		{
			get { return MIMEHeader["Via"]; }
			set { MIMEHeader["Via"] = value; }
		}
		
		// This isn't always a valid Guid... so use a string
		// eg. the Encarta Instant Answers bot sends 2 Guids stuck together
		public string Branch
		{
			get { return MIMEHeader["Via"]["branch"]; }
			set { MIMEHeader["Via"]["branch"] = value; }
		}
		
		public int CSeq
		{
			get { return int.Parse (MIMEHeader["CSeq"]); }
			set { MIMEHeader["CSeq"] = value.ToString(); }
		}
		
		public Guid CallID
		{
			get { return new Guid (MIMEHeader["Call-ID"]); }
			set { MIMEHeader["Call-ID"] = value.ToString ("B").ToUpper (System.Globalization.CultureInfo.InvariantCulture); }
		}
		
		public int MaxForwards
		{
			get { return int.Parse (MIMEHeader["Max-Forwards"]); }
			set { MIMEHeader["Max-Forwards"] = value.ToString (); }
		}
		
		public string ContentType
		{
			get { return MIMEHeader["Content-Type"]; }
			set { MIMEHeader["Content-Type"] = value; }
		}
		
		public SLPMessage (IMsnEntity to)
		{
			_session = to.Session as MsnSession;

			To = to;
			From = _session.Account;
			Via = "MSNSLP/1.0/TLP";
			Branch = Guid.NewGuid ().ToString ("B").ToUpperInvariant ();
			CSeq = 0;
			CallID = Guid.NewGuid ();
			MaxForwards = 0;
			ContentType = "text/unknown";
			_mimeHeader["Content-Length"] = "0";
		}
		
		public SLPMessage (MsnSession session, byte[] data)
		{
			_session = session;
			
			int lineLen = MsnByteArrayUtility.IndexOf (data, "\r\n");
			byte[] lineData = new byte[lineLen];
			Array.Copy (data, lineData, lineLen);
			StartLine = Encoding.UTF8.GetString (lineData);
			
			byte[] header = new byte[data.Length - lineLen - 2];
			Array.Copy (data, lineLen + 2, header, 0, header.Length);
			
			_mimeHeader.Clear ();
			int mimeEnd = _mimeHeader.Parse (header);
			
			byte[] body = new byte[header.Length - mimeEnd];
			Array.Copy (header, mimeEnd, body, 0, body.Length);
			
			_mimeBody.Clear ();
			_mimeBody.Parse (body);
		}
		
		public byte[] ToByteArray ()
		{
			byte[] body = Encoding.UTF8.GetBytes (_mimeBody.ToString ());
			
			// Update the Content-Length header
			// _mimeBody length + \r\n\0
			_mimeHeader["Content-Length"] = (body.Length + 3).ToString ();
			
			MessageBuilder mb = new MessageBuilder ();
			
			mb.Append (StartLine);
			mb.Append (_mimeHeader.ToString ());
			mb.Append ("\r\n");
			mb.Append (body);
			mb.Append ("\r\n");
			mb.Append (new byte[] { 0 });
			
			return mb.GetByteArray ();
		}
	}
}
